package com.hboxs.asl.controller.wechat;

import com.hboxs.asl.entity.Member;
import com.hboxs.asl.service.MemberRankService;
import com.hboxs.asl.service.MemberService;
import com.hboxs.asl.wechat.WechatConfig;
import com.hboxs.asl.wechat.WxCoreService;
import com.hboxs.asl.wechat.entity.Wechat;
import com.hboxs.asl.wechat.entity.WxUserInfo;
import com.hboxs.asl.wechat.service.WechatService;
import com.hboxs.asl.wechat.service.WxConfigService;
import com.hboxs.asl.wechat.utils.BeanUtils;
import com.hboxs.asl.wechat.utils.WechatUtils;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Enumeration;

/**
 * Created by study on 6/25/2015.
 */
@Controller("wechatController")
@RequestMapping("/wechat")
public class WechatController {
    protected Logger logger = Logger.getLogger(getClass().getName());

    @Resource(name = "wxConfigServiceImpl")
    private WxConfigService wxConfigService;
    @Resource(name = "wxCoreService")
    private WxCoreService wxCoreService;
    @Resource(name = "memberServiceImpl")
    private MemberService memberService;
    @Resource(name = "memberRankServiceImpl")
    private MemberRankService memberRankService;
    @Resource(name = "wechatServiceImpl")
    private WechatService wechatService;


    @RequestMapping(value = "/manage", method = RequestMethod.GET)
    public
    @ResponseBody
    String manage(String signature, String timestamp, String nonce, String echostr) {
        logger.info("== Start Wechat Manage Get ==");

        String rst = null;

        try {
            WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(WechatConfig.TOKEN, WechatConfig.ENCODING_AES_KEY, WechatConfig.APP_ID);
            wxBizMsgCrypt.verifyUrl(signature, timestamp, nonce);
            rst = echostr;
        } catch (AesException e) {
            logger.error("Message does not from Wechat Server.");
        }

        logger.info("== Ended Wechat Manage Get ==");

        return rst;
    }

    @RequestMapping(value = "/manage", method = RequestMethod.POST)
    public
    @ResponseBody
    String manage(String signature, String timestamp, String nonce, String echostr, HttpServletRequest request) throws ServletException, IOException {
        logger.info("== Start Wechat Manage Post ==");

        request.setCharacterEncoding("UTF-8");
        String rst = null;
        Enumeration reqEnums = request.getParameterNames();
        while (reqEnums.hasMoreElements()) {
            String param = reqEnums.nextElement().toString();
            logger.info("Request Parameter:" + param + "=" + request.getParameter(param));
        }

        try {
            WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(WechatConfig.TOKEN, WechatConfig.ENCODING_AES_KEY, WechatConfig.APP_ID);
            logger.info("Verified URL:" + wxBizMsgCrypt.verifyUrl(signature, timestamp, nonce));

            String response = wxCoreService.processRequest(request);

            if (StringUtils.isEmpty(response)) {
                rst = echostr;
            } else {
                rst = wxBizMsgCrypt.encryptMsg(response, timestamp, nonce);
            }
        } catch (Exception e) {
            logger.error("Message does not from Wechat Server.");
        }

        logger.info("Response to Server:" + rst);
        logger.info("== Ended Wechat Manage Post ==");

        return rst;
    }

    @RequestMapping(value = "/qrcode-create-forever", method = RequestMethod.GET)
    public
    @ResponseBody
    String qrcodeCreateForever(String id) {
        String rst;
        if (StringUtils.isEmpty(id)) id = "1";
        String datafmt = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"%s\"}}}";
        JSONObject data = new JSONObject(String.format(datafmt, id));
        data = WechatUtils.qrcode_creation(wxConfigService.latestAccessToken(), data);
        rst = data.toString();

        return rst;
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(String scope, String callback, HttpServletRequest request) {

        try {
            String encoding = "UTF-8";

            if (StringUtils.isEmpty(scope)) scope = WechatUtils.SNSAPI_BASE;

            if (StringUtils.isEmpty(callback)) {
                callback = "http://haixian.hboxs.com/wechat/callback.htm";
            } else {
                callback = "http://haixian.hboxs.com/wechat/callback.htm?redirect_url=" + callback;
            }

            String url = WechatUtils.wechatLoginUrl(
                    WechatConfig.APP_ID,
                    URLEncoder.encode(callback, encoding),
                    scope,
                    DigestUtils.md5Hex(request.getSession().getId())
            );
            return "redirect:" + url;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "redirect:/m/login.htm";
    }

    /**
     * 跳转登录
     * @param request
     * @return
     */
    @RequestMapping(value = "/member/login", method = RequestMethod.GET)
    public String memberLogin(HttpServletRequest request) {
        return "/yijing/login";
    }

    /**
     * 跳转忘记密码
     * @param request
     * @return
     */
    @RequestMapping(value = "/member/login-forget", method = RequestMethod.GET)
    public String memberLoginForget(HttpServletRequest request) {
        return "/yijing/login-forget";
    }

    /**
     * 跳转注册
     * @param request
     * @return
     */
    @RequestMapping(value = "/member/register", method = RequestMethod.GET)
    public String memberRegister( HttpServletRequest request) {
        return "/yijing/register";
    }

    @RequestMapping(value = "/callback", method = RequestMethod.GET)
    public String callback(String redirect_url, String code, String state, HttpServletRequest request) {
//        logger.info("Code:" + code + ", State:" + state);
        try {
            // 检查状态
            if (DigestUtils.md5Hex(request.getSession().getId()).equals(state)) {

                // 获取access token
                JSONObject json = WechatUtils.accessTokenUrl(
                        WechatConfig.APP_ID,
                        WechatConfig.APP_SECRET,
                        code
                );

                Wechat wechat = new Wechat();

                if (json.has("access_token")) wechat.setAccessToken(json.getString("access_token"));
                if (json.has("expires_in")) wechat.setExpiresIn(json.getInt("expires_in"));
                if (json.has("refresh_token")) wechat.setRefreshToken(json.getString("refresh_token"));
                if (json.has("openid")) {
                    wechat.setOpenid(json.getString("openid"));
                }
                if (json.has("scope")) wechat.setScope(json.getString("scope"));
                if (json.has("errcode")) {
                    logger.error(json.toString());
                } else {
                    logger.info(json.toString());
                }


                // 保存用户
                Member member = memberService.findByUsername(wechat.getOpenid());
                if (member == null) {
                    // 新用户
                    saveMember(wechat, request);
                } else {
                    // 更新用户
                    updateWechat(wechat, member);
                }

                return "redirect:/weChat/member/autoLogin.htm?redirect_url=" + redirect_url + "&username=" + wechat.getOpenid();
            } else {
//                logger.info("Your state is invalid!!!");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return "redirect:/404.html";
    }

    /**
     * 保存用户
     *
     * @param wechat
     * @param request
     */
    private void saveMember(Wechat wechat, HttpServletRequest request) {
        logger.info("== Save Member Start ==");
        try {
            Member member = new Member();
            member.setUsername(wechat.getOpenid());
            member.setPassword(DigestUtils.md5Hex(wechat.getOpenid()));
            member.setEmail("@");
            member.setIsEnabled(true);
            member.setIsLocked(false);
            member.setLoginFailureCount(0);
            member.setBalance(new BigDecimal(0));
            member.setLockedDate(null);
            member.setPoint(new BigDecimal(0));
            member.setRegisterIp(request.getRemoteAddr());
            member.setLoginIp(request.getRemoteAddr());
            member.setLoginDate(new Date());
            member.setSafeKey(null);
            member.setMemberRank(memberRankService.findDefault());
            memberService.save(member);

            // 更新微信
            updateWechat(wechat, member);
        } catch (Exception e) {
            e.printStackTrace();
        }

        logger.info("== Save Member Ended ==");
    }

    private void updateWechat(Wechat wechat, Member member) {
        logger.info("== Update Wechat Start ==");

        Wechat targetWechat = member.getWechat();

        // update wechat
        if (targetWechat == null) {
            targetWechat = wechat;
            targetWechat.setMember(member);
            wechatService.save(targetWechat);
        } else {
            BeanUtils.copyProperties(wechat, targetWechat);
        }

        // 尝试已订阅用户
        WxUserInfo wxUserInfo = WechatUtils.userinfo(wxConfigService.latestAccessToken(), targetWechat.getOpenid(), true);

        if (wxUserInfo.getSubscribe() != 1) {
//            logger.info("User does not subscribed!");
            // 未订阅用户
            wxUserInfo = WechatUtils.userinfo(targetWechat.getAccessToken(), targetWechat.getOpenid(), false);
        } else {
//            logger.info("User has been subscribed!");
        }
        wechatService.update(targetWechat, wxUserInfo);

        logger.info("== Update Wechat Ended ==");
    }
}
